home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / PTMID3.ZIP / PTMIDINP.C < prev    next >
C/C++ Source or Header  |  1994-07-05  |  15KB  |  534 lines

  1. /*
  2.  * ptmidinp.c: MIDI input module for for ptmid. Reads a MIDI file and
  3.  * creates a structure representing it.
  4.  *
  5.  * Author: Andrew Scott  (c)opyright 1994
  6.  *
  7.  * Date: 17/11/1993 ver 0.0
  8.  *       8/1/1994   ver 0.1
  9.  *       11/2/1994  ver 0.2
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <io.h>
  15. #include <fcntl.h>
  16. #include <string.h>
  17. #include "ptmid.h"
  18.  
  19. #define BUFSIZ 512
  20.  
  21. #define ODD(x) (x & 1)
  22.  
  23. typedef unsigned long VLQ; /** VLQ is a variable length quantity **/
  24.  
  25. typedef struct { /** RF is a record of a file **/
  26.   int fd, ib;
  27.     unsigned char rgb[BUFSIZ];
  28. } RF;
  29.  
  30. int rgbPatch[16], wDivision, wBendsen = 2, wModwheel = 0;
  31. unsigned wQuant;
  32. NRL *rgpnrl[16][128];
  33. Tune *ptuneMain, *ptuneCurr;
  34. RF *prf;
  35.  
  36. /*
  37.  * Init: Yes.. you guessed it. Initializes variables and stuff.
  38.  *
  39.  * date: 30/6/1994 - added 16 NRL array init
  40.  */
  41. static void Init(void)
  42. {
  43.   int i, j;
  44.  
  45.   for (i = 16; i--; ) { /** Clear current instrument array **/
  46.         rgbPatch[i] = 0;
  47.     for (j = 128; j--; ) /** Clear hanging-note arrays **/
  48.       rgpnrl[i][j] = NULL;
  49.   }
  50. }
  51.  
  52. /*
  53.  * ChGetFd: Given a file, returns next character from it.
  54.  */
  55. int ChGetFd(int fd)
  56. {
  57.     unsigned char b;
  58.  
  59.     if (read(fd, &b, 1) < 1)
  60.         return EOF;
  61.     return b;
  62. }
  63.  
  64. /*
  65.  * ChGetIrf: Given an index, returns next character from corresponding
  66.  * file record.
  67.  */
  68. unsigned char ChGetIrf(unsigned irf)
  69. {
  70.     if (prf[irf].ib == BUFSIZ) {
  71.         if (read(prf[irf].fd, prf[irf].rgb, BUFSIZ) == -1) {
  72.             ERROR;
  73.             exit(1);
  74.         }
  75.         prf[irf].ib = 1;
  76.         return prf[irf].rgb[0];
  77.     }
  78.     return prf[irf].rgb[prf[irf].ib++];
  79. }
  80.  
  81. /*
  82.  * SkipIrf: Given an index, skips a given number of bytes forward in
  83.  * that file record.
  84.  *
  85.  * date: 4/7/1994 - fixed longstanding bug: wouldn't read in new buffer
  86.  */
  87. void SkipIrf(unsigned irf, long cb)
  88. {
  89.   if (BUFSIZ - prf[irf].ib >= cb)
  90.     prf[irf].ib += (int) cb;
  91.     else {
  92.         cb -= BUFSIZ - prf[irf].ib;
  93.     if (lseek(prf[irf].fd, cb, SEEK_CUR) == -1) {
  94.             ERROR;
  95.             exit(1);
  96.         }
  97.     prf[irf].ib = BUFSIZ;
  98.     }
  99. }
  100.  
  101. /*
  102.  * ValidquantSz: Takes a lower-case string and checks to see if it is a
  103.  * legal quantize fraction. If not, zero is returned, else value of
  104.  * string is returned (+1 if a triplet case).
  105.  */
  106. int ValidquantSz(Sz szQuant)
  107. {
  108.     int bFrac;
  109.     Sz szEnd;
  110.  
  111.   if ((bFrac = (int) strtol(szQuant, &szEnd, 10))) /** If a number **/
  112.         if ('t' == *szEnd || 'T' == *szEnd) /** possibly followed by a 't' **/
  113.             bFrac++;
  114.     return bFrac; /** return valid **/
  115. }
  116.  
  117. /*
  118.  * VlqFromFd: Reads bytes from given file until a variable length
  119.  * quantity is decoded. Returns that vlq.
  120.  */
  121. VLQ VlqFromFd(int fd)
  122. {
  123.     VLQ vlqRead = 0;
  124.     unsigned char b = 0;
  125.  
  126.     while (read(fd, &b, 1) == 1 && (b & 0x80))
  127.         vlqRead = (vlqRead << 7) | (b & 0x7F);
  128.     return (vlqRead << 7) | b;
  129. }
  130.  
  131. /*
  132.  * VlqFromIrf: Reads bytes from file corresponding to given index until
  133.  * a variable length quantity is decoded. Returns that vlq.
  134.  */
  135. VLQ VlqFromIrf(unsigned irf)
  136. {
  137.     VLQ vlqRead = 0;
  138.     unsigned char b = 0;
  139.  
  140.     while ((b = ChGetIrf(irf)) & 0x80)
  141.         vlqRead = (vlqRead << 7) | (b & 0x7F);
  142.     return (vlqRead << 7) | b;
  143. }
  144.  
  145. /*
  146.  * LongFromFd: Reads number of bytes from Fd until number is in.
  147.  */
  148. unsigned long LongFromFd(int fd, unsigned cb)
  149. {
  150.     unsigned char rgb[4];
  151.     unsigned long longT = 0;
  152.     unsigned ib = 0;
  153.  
  154.     read(fd, rgb, cb);
  155.     for (; ib < cb; ib++)
  156.         longT = (longT << 8) + rgb[ib];
  157.     return longT;
  158. }
  159.  
  160. /*
  161.  * Addnote: Given channel, pitch, instrument, and volume will add that
  162.  * note to the array of playing notes.
  163.  *
  164.  * date: 30/6/1994 - added chan as well as pfx init
  165.  */
  166. void Addnote(int chan, int pitch, int inst, int vol)
  167. {
  168.     NRL *pnrlT;
  169.  
  170.   if (0 > pitch || 127 < pitch || 0 > chan || 15 < chan)
  171.         return;
  172.     pnrlT = (NRL *) malloc(sizeof(NRL)); /** Allocate space **/
  173.   pnrlT->pnrl = rgpnrl[chan][pitch];
  174.   rgpnrl[chan][pitch] = pnrlT; /** Attach to front of list in array **/
  175.     pnrlT->inst = inst;
  176.     pnrlT->vol = vol;
  177.   pnrlT->pfxTail = NULL;
  178.     pnrlT->ptuneNow = ptuneCurr;
  179. }
  180.  
  181. /*
  182.  * PeiRequestPtune: Returns a pointer to a new event structure at the
  183.  * position in the tune specified.
  184.  */
  185. EI *PeiRequestPtune(Tune *ptune)
  186. {
  187.     EI *pei;
  188.  
  189.     pei = (EI *) malloc(sizeof(EI)); /** Allocate space for event **/
  190.   pei->pei = ptune->pei;
  191.   ptune->pei = pei; /** Attach to front of event list at tune position **/
  192.     return pei;
  193. }
  194.  
  195. /*
  196.  * Endnote: Given a pitch and instrument, will remove a note from array
  197.  * of playing notes and store it as an event in the tune.
  198.  *
  199.  * date: 30/6/1994 - added support for effects, 16 chans, min. perc. durat.
  200.  */
  201. void Endnote(int chan, int pitch, int inst)
  202. {
  203.   NRL *pnrlT, *pnrlOld = NULL;
  204.     unsigned long durat;
  205.     EI *peiT;
  206.  
  207.   if (0 > pitch || 127 < pitch || 0 > chan || 15 < chan)
  208.         return;
  209.   for (pnrlT = rgpnrl[chan][pitch]; NULL != pnrlT && pnrlT->inst != inst; ) {
  210.         pnrlOld = pnrlT;
  211.         pnrlT = pnrlT->pnrl;
  212.     } /** Find instrument in hanging-note array **/
  213.     if (NULL == pnrlT)
  214.         return;
  215.  
  216.   durat = ptuneCurr->count - pnrlT->ptuneNow->count; /** Calc. duration **/
  217.   if (0 > inst && wDivision / 2 > durat)
  218.     durat = wDivision / 2; /** Percussion sounds have a min. duration **/
  219.   if (durat < wQuant)
  220.     durat = wQuant; /** All sounds have a min. duration **/
  221.  
  222.   peiT = PeiRequestPtune(pnrlT->ptuneNow); /** Get an event **/
  223.   peiT->effect = durat;
  224.   peiT->inst = inst; /** Store the note in it **/
  225.   peiT->pitch = pitch;
  226.   peiT->vol = pnrlT->vol;
  227.   peiT->pfxTail = pnrlT->pfxTail;
  228.  
  229.   if (NULL == pnrlOld) /** Remove note from hanging-note array **/
  230.     rgpnrl[chan][pitch] = pnrlT->pnrl;
  231.     else
  232.         pnrlOld->pnrl = pnrlT->pnrl;
  233.     free(pnrlT);
  234. }
  235.  
  236. /*
  237.  * VlqInterpIrf: Reads a file pointer and gathers all notes at this
  238.  * instant, storing them on the note stack. Returns ticks until next
  239.  * collection of notes. A running status of current channel is maintained.
  240.  *
  241.  * date: 30/6/1994 - added effect support
  242.  */
  243. VLQ VlqInterpIrf(unsigned irf, unsigned *pbStat)
  244. {
  245.     unsigned bEvent;
  246.     VLQ vlqT;
  247.   FX *pfx;
  248.  
  249.     do { /** Loop.. **/
  250.         bEvent = ChGetIrf(irf); /** Get first data byte **/
  251.         if (0x80 <= bEvent && 0xEF >= bEvent) { /** If a command **/
  252.             *pbStat = bEvent; /** update running-status byte **/
  253.             bEvent = ChGetIrf(irf); /** and get next data byte **/
  254.         }
  255.         if (0xF0 == bEvent || 0xF7 == bEvent) /** If a sys-exclusive message **/
  256.             SkipIrf(irf, VlqFromIrf(irf)); /** skip it **/
  257.         else if (0xFF == bEvent) { /** Else if a meta event **/
  258.             bEvent = ChGetIrf(irf); /** get type of event **/
  259.             vlqT = VlqFromIrf(irf); /** and length **/
  260.             if (0x2F == bEvent) { /*** If termination event ***/
  261.                 close(prf[irf].fd); /*** close handle ***/
  262.                 prf[irf].fd = -1;
  263.                 vlqT = 0;
  264.                 break; /*** and terminate ***/
  265.             }
  266.             if (0x51 == bEvent) { /*** Else if tempo event ***/
  267.                 unsigned long t;
  268.                 EI *pei;
  269.  
  270.                 t = (unsigned long) ChGetIrf(irf) << 16; /*** get value ***/
  271.                 t += (unsigned long) ChGetIrf(irf) << 8;
  272.                 t += ChGetIrf(irf);
  273.                 pei = PeiRequestPtune(ptuneCurr);
  274.                 pei->effect = 60000000L / wQuant * wDivision / t; /*** and convert ***/
  275.         pei->pitch = -1;
  276.             } else
  277.                 SkipIrf(irf, vlqT); /*** Else skip event ***/
  278.         } else
  279.             switch (*pbStat & 0xF0) { /** Else must be a midi event.. **/
  280.                 case 0x80:
  281.                 case 0x90: { /** Note on/off **/
  282.                     unsigned bVol, bChan;
  283.  
  284.                     bVol = ChGetIrf(irf);
  285.                     bChan = *pbStat & 0x0F;
  286.                     if (0 < bVol && 0x90 <= *pbStat)
  287.                         if (bChan != bDrumch)
  288.               Addnote(bChan, bEvent, rgbPatch[bChan], bVol);
  289.                         else
  290.               Addnote(bChan, 0, -1 - bEvent, bVol);
  291.                     else
  292.                         if (bChan != bDrumch)
  293.               Endnote(bChan, bEvent, rgbPatch[bChan]);
  294.                         else
  295.               Endnote(bChan, 0, -1 - bEvent);
  296.                     break;
  297.                 }
  298.         case 0xA0: { /** Polyphonic Key Pressure **/
  299.           NRL *pnrlT;
  300.           unsigned bChan;
  301.  
  302.           bChan = *pbStat & 0x0F;
  303.           pnrlT = rgpnrl[bChan][bEvent];
  304.           while (NULL != pnrlT && pnrlT->inst != rgbPatch[bChan])
  305.             pnrlT = pnrlT->pnrl;
  306.           if (NULL != pnrlT) {
  307.             pfx = (FX *) malloc(sizeof(FX));
  308.             pfx->delay = ptuneCurr->count - pnrlT->ptuneNow->count;
  309.             pfx->eff = 1;
  310.             pfx->param = ChGetIrf(irf);
  311.             if (NULL == pnrlT->pfxTail)
  312.               pfx->pfx = pfx;
  313.             else {
  314.               pfx->pfx = pnrlT->pfxTail->pfx;
  315.               pnrlT->pfxTail->pfx = pfx;
  316.             }
  317.             pnrlT->pfxTail = pfx;
  318.           } else
  319.             ChGetIrf(irf);
  320.           break;
  321.         }
  322.         case 0xB0: { /** Controller change **/
  323.           int bValue;
  324.  
  325.           bValue = ChGetIrf(irf);
  326.           switch (bValue) {
  327.             case 1: /*** Modulation wheel (ie. vibrato) ***/
  328.               wModwheel = bValue;
  329.               break;
  330.             case 6: /*** Pitch bend sensativity ***/
  331.               wBendsen = bValue;
  332.               break;
  333.           }
  334.           break;
  335.         }
  336.                 case 0xE0: /** Pitch Wheel change **/
  337.                     ChGetIrf(irf);
  338.                     break;
  339.                 case 0xC0: /** Program change **/
  340.                     rgbPatch[*pbStat - 0xC0] = bEvent;
  341.                     break;
  342.                 case 0xD0: /** Channel Pressure **/
  343.                     break;
  344.             }
  345.         vlqT = VlqFromIrf(irf);
  346.     } while (0 == vlqT); /** Continue loop for simultaneous notes **/
  347.     return vlqT;
  348. }
  349.  
  350. /*
  351.  * Freearray: Performs a free on all structures left in rgpnrl array.
  352.  * Assume these notes are rebels.
  353.  *
  354.  * date: 30/6/1994 - now frees remaining fx too
  355.  */
  356. void Freearray(void)
  357. {
  358.   int i, j = 16;
  359.     NRL *pnrlT, *pnrlT2;
  360.   FX *pfxT, *pfxT2;
  361.  
  362.   while (j--) /** Go through hanging-note array **/
  363.     for (i = 128; i--; )
  364.       for (pnrlT = rgpnrl[j][i]; NULL != pnrlT; ) { /** freeing each list **/
  365.         pnrlT2 = pnrlT->pnrl;
  366.         pfxT = pnrlT->pfxTail->pfx;
  367.         if (NULL != pfxT) {
  368.           while (pfxT != pnrlT->pfxTail) { /** and each fx list **/
  369.             pfxT2 = pfxT;
  370.             pfxT = pfxT->pfx;
  371.             free(pfxT2);
  372.           }
  373.           free(pfxT);
  374.         }
  375.         free(pnrlT);
  376.         pnrlT = pnrlT2;
  377.       }
  378. }
  379.  
  380. /*
  381.  * PtuneLoadPfile: Given the filename of a MIDI file, parse it and return
  382.  * a pointer to a collection of chords (a Tune structure). If MIDI file
  383.  * cannot be processed, NULL is returned.
  384.  */
  385. Tune *PtuneLoadFn(Sz FnMIDI)
  386. {
  387.     int fd, crf;
  388.     unsigned long cb, *pvlqWait, vlqMin = -1, vlqT, wCount, wNcount, cDev = 0;
  389.     unsigned irf, irfMax, *pbStatus, wQuant2, wDev, wMaxdev = 0, cMaxdev = 0;
  390.     char rgbHeader[9] = {'M', 'T', 'h', 'd', 0, 0, 0, 6, 0}, rgbTest[9];
  391.  
  392.     Init();
  393.     fd = open(FnMIDI, O_RDONLY | O_BINARY);
  394.     read(fd, rgbTest, 9);
  395.     if (memcmp(rgbHeader, rgbTest, 9) || ChGetFd(fd) > 1) {
  396.         close(fd);
  397.         return NULL; /** Only process type 0 or type 1 general MIDI files **/
  398.     }
  399.  
  400.   irfMax = (unsigned) LongFromFd(fd, 2); /** Get # tracks **/
  401.   wDivision = (int) LongFromFd(fd, 2); /** Get ticks for a beat **/
  402.  
  403.     if (-1 == lseek(fd, 23, SEEK_SET)) {
  404.         close(fd);
  405.         return NULL; /** Error if MIDI file is smaller than 23 bytes **/
  406.     }
  407.     if (fNocopy && ChGetFd(fd) == 0xFF && ChGetFd(fd) == 0x02) {
  408.         close(fd);
  409.         if (!fQuiet)
  410.             printf("** NOCOPY option set and copyright notice found in file **\n");
  411.         return NULL; /** Error if Nocopy and copyright notice exists **/
  412.     }
  413.     if (32767 < wDivision) {
  414.         if (!fQuiet)
  415.             printf("** Slack programmer error -- SMPTE frames not supported **\n");
  416.         close(fd);
  417.         return NULL;
  418.     }
  419.  
  420.     if (ODD(wQuantval)) /** Calculate quantize ticks from quantize fraction **/
  421.         wQuant = wDivision * 8 / (3 * (wQuantval - 1));
  422.     else
  423.         wQuant = wDivision * 4 / wQuantval;
  424.     wQuant2 = wQuant/2;
  425.     if (fStats) {
  426.         printf(" Ticks to quantize: %u\n", wQuant);
  427.         printf(" Number of tracks: %d\n", irfMax);
  428.     }
  429.  
  430.     prf = (RF *) malloc(sizeof(RF) * irfMax);
  431.     pvlqWait = (VLQ *) malloc(sizeof(VLQ) * irfMax);
  432.     pbStatus = (unsigned *) malloc(sizeof(unsigned) * irfMax);
  433.  
  434.     lseek(fd, 18, SEEK_SET);
  435.     /** Put file descriptors at the start of each track in file **/
  436.     for (irf = 0; !eof(fd) && irf < irfMax; irf++) {
  437.         cb = LongFromFd(fd, 4);
  438.         if ((prf[irf].fd = open(FnMIDI, O_RDONLY | O_BINARY)) == -1) {
  439.             ERROR;
  440.             exit(1);
  441.         }
  442.         lseek(prf[irf].fd, tell(fd), SEEK_SET);
  443.         read(prf[irf].fd, prf[irf].rgb, BUFSIZ);
  444.         prf[irf].ib = 0;
  445.         if ((pvlqWait[irf] = VlqFromIrf(irf)) < vlqMin)
  446.             vlqMin = pvlqWait[irf]; /** Find minimum time to first event **/
  447.         pbStatus[irf] = 0x90;
  448.         lseek(fd, cb + 4, SEEK_CUR);
  449.     }
  450.     close(fd);
  451.     if (irf != irfMax) { /** If things look a bit suspicious **/
  452.         printf("** MIDI file ends prematurely **\n");
  453.         free(prf); /** Free prf - NB. not closed **/
  454.         free(pvlqWait);
  455.         free(pbStatus);
  456.         return NULL;
  457.     }
  458.  
  459.     ptuneMain = ptuneCurr = (Tune *) malloc(sizeof(Tune));
  460.     wCount = vlqMin; /** Start from first event **/
  461.     wNcount = (wCount + wQuant2) % wQuant;
  462.     if (fStats) {
  463.     wDev = abs(wQuant2 - (int) wNcount);
  464.         if (wDev > 2)
  465.             cDev++;
  466.         if (wDev > wMaxdev) {
  467.             wMaxdev = wDev;
  468.             cMaxdev = 1;
  469.         } else if (wDev == wMaxdev)
  470.             cMaxdev++;
  471.     }
  472.     ptuneMain->count = wCount + wQuant2 - wNcount;
  473.     wNcount = wQuant - wNcount;
  474.     ptuneMain->ptune = NULL;
  475.     ptuneMain->pei = NULL;
  476.     crf = 1;
  477.     while (0 < crf) { /** While still tracks in file to process **/
  478.         crf = 0;
  479.         vlqT = -1;
  480.         for (irf = 0; irf < irfMax; irf++) /** With each track.. **/
  481.             if (-1 != prf[irf].fd) { /** If not finished **/
  482.                 crf++;
  483.                 /**
  484.                  ** Must keep all tracks in sync, if events occurring on this track
  485.                  ** at this instant, then interpret them. Also note when next event
  486.                  ** will occur (ie. minimum ticks to next event)
  487.                  **/
  488.                 if ((pvlqWait[irf] -= vlqMin) == 0)
  489.                     pvlqWait[irf] = VlqInterpIrf(irf, pbStatus + irf);
  490.                 if (pvlqWait[irf] < vlqT)
  491.                     vlqT = pvlqWait[irf];
  492.             }
  493.  
  494.         vlqMin = vlqT;
  495.         wCount += vlqMin;
  496.         if (wNcount <= vlqMin) { /** If need to advance to new quanta **/
  497.             if ((ptuneCurr->ptune = (Tune *) malloc(sizeof(Tune))) == NULL) {
  498.                 ERROR;
  499.                 exit(1);
  500.             } /** allocate **/
  501.             ptuneCurr = ptuneCurr->ptune; /** and initialize **/
  502.             wNcount = (wCount + wQuant2) % wQuant;
  503.             if (fStats) {
  504.         wDev = abs(wQuant2 - (int) wNcount);
  505.                 if (wDev > 2)
  506.                     cDev++;
  507.                 if (wDev > wMaxdev) {
  508.                     wMaxdev = wDev;
  509.                     cMaxdev = 1;
  510.                 } else if (wDev == wMaxdev)
  511.                     cMaxdev++;
  512.             }
  513.             ptuneCurr->count = wCount + wQuant2 - wNcount;
  514.             wNcount = wQuant - wNcount;
  515.             ptuneCurr->ptune = NULL;
  516.             ptuneCurr->pei = NULL;
  517.         } else
  518.             wNcount -= vlqMin; /** Else decrememnt "new quanta" count **/
  519.     }
  520.  
  521.     Freearray();
  522.     free(pvlqWait);
  523.     free(pbStatus);
  524.     free(prf);
  525.  
  526.     if (fStats) {
  527.         printf(" Maximum quantize error: %u\n", wMaxdev);
  528.         printf(" Number of times it occurred: %u\n", cMaxdev);
  529.         printf(" Number of times quantize error > 2 occurred: %lu\n", cDev);
  530.     }
  531.  
  532.     return ptuneMain;
  533. }
  534.